﻿using NDK.AcqDevice;
using DALSA.SaperaLT.SapClassBasic;
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Threading;
using System.Windows.Forms;

namespace NDK.Module.Model
{
    public class DalsaCam
    {
        public bool bGrabed = false;
        public bool bParaSet = true;
        public Bitmap m_bitmap;
        //public SapBuffer buffEx;
        SapAcqToBuf toBuff;
        SapBufferWithTrash buffTrash;
        SapAcquisition acq;
        SapAcqDevice dev;
        string sServer;
        string rotateAngle = "0";
        public Point ptCrop;
        public Size sizeCrop;

        public CamSight camSight;

        public bool bCrop = false;


        public string InitCard()
        {
            string sMsg = "";
            //获取卡数量
            int nServer = SapManager.GetServerCount();
            if (nServer <= 0) { sMsg += "Can't Find Camera Card\n"; return sMsg; }

            //获取卡上有几个相机
            //for (int i = 0; i < nServer; i++)
            //{
            //    sServer = SapManager.GetServerName(i);//获取卡名称
            //}
            sServer = SapManager.GetServerName(1);//获取卡名称
            int nResource = SapManager.GetResourceCount(sServer, SapManager.ResourceType.Acq);
            if (nResource < 2) { sMsg += $"Find {nResource} Camera of 2\n"; return sMsg; }

            //SapLocation loc1 = new SapLocation(sServer, 1);
            //acq = new SapAcquisition(loc1, configPath1);
            //buffTrash = new SapBufferWithTrash(2, acq, SapBuffer.MemoryType.ScatterGather);
            //toBuff = new SapAcqToBuf(acq, buffTrash);

            //bool bAcq = acq.Create();
            //bool bBuff = buffTrash.Create();
            ////buffEx = new SapBuffer(2, buffTrash.Width, buffTrash.Height, SapFormat.RGB888, SapBuffer.MemoryType.Default);
            ////bool bBuffEx = buffEx.Create();
            //bool bToBuff = toBuff.Create();
            //SapLocation sapLoc = new SapLocation("CameraLink_1", 0);
            //SapAcqDevice dev = new SapAcqDevice(sapLoc, false);
            //dev.Create();
            //dev.SetFeatureValue("ExposureTime", "99");
            //dev.SetFeatureValue("Gain", "10");
            //dev.GetFeatureValue("TriggerMode", out string ns);
            //dev.SetFeatureValue("TriggerMode", "On");

            ////toBuff.Pairs[0].EventType = SapXferPair.XferEventType.EndOfFrame;
            //toBuff.XferNotify += new SapXferNotifyHandler(xfer_XferNotify);
            //toBuff.XferNotifyContext = this;

            return sMsg == "" ? "OK" : sMsg;
        }

        public string InitCamera(int camIndex, string configPath, string camLinkName)
        {
            try
            {
                SapLocation loc1 = new SapLocation(sServer, camIndex);
                acq = new SapAcquisition(loc1, configPath);
                buffTrash = new SapBufferWithTrash(2, acq, SapBuffer.MemoryType.ScatterGather);
                toBuff = new SapAcqToBuf(acq, buffTrash);

                bool bAcq = acq.Create();
                bool bBuff = buffTrash.Create();


                //buffEx = new SapBuffer(2, buffTrash.Width, buffTrash.Height, SapFormat.RGB888, SapBuffer.MemoryType.Default);
                //bool bBuffEx = buffEx.Create();
                bool bToBuff = toBuff.Create();
                SapLocation sapLoc = new SapLocation(camLinkName, 0);
                dev = new SapAcqDevice(sapLoc, false);
                dev.Create();

                //dev.SetFeatureValue("ExposureTime", "100");
                //dev.SetFeatureValue("Gain", "1");
                //dev.GetFeatureValue("TriggerMode", out string ns);
                dev.SetFeatureValue("TriggerMode", "On");
                dev.SetFeatureValue("ClConfiguration", "Base");
                //dev.SetFeatureValue("Image Height", 1000);
                //dev.SetFeatureValue(SapFeature.rate, true);
                //dev.SendCommand("",)
                //toBuff.Pairs[0].EventType = SapXferPair.XferEventType.EndOfFrame;
                toBuff.XferNotify += new SapXferNotifyHandler(xfer_XferNotify);
                toBuff.XferNotifyContext = this;

                return "OK";
            }
            catch (Exception ex)
            {
                return ex.Message;
            }

        }
        public int GetLineRate()
        {
            var Line_Rate_Feature = 0;
            var b = dev.GetFeatureValue("measureLineRate", out Line_Rate_Feature);
            //b = dev.GetFeatureValue("Measured Line Rate", out Line_Rate_Feature);
            if (b) return Line_Rate_Feature;
            else return -1;
        }

        public enum EnumEncoder
        {
            A, B
        }
        public void SwitchEncoder(EnumEncoder encoder)
        {
            try
            {
                if (encoder == EnumEncoder.A)
                    acq.SetParameter(SapAcquisition.Prm.EXT_TRIGGER_SOURCE, SapAcquisition.Val.SIGNAL_NAME_SHAFT_ENCODER_PHASE_A, true);
                else
                    acq.SetParameter(SapAcquisition.Prm.EXT_TRIGGER_SOURCE, SapAcquisition.Val.SIGNAL_NAME_SHAFT_ENCODER_PHASE_B, true);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }

        public void EnableExternelTrigger(bool bEnable)
        {
            try
            {
                if (bEnable)
                    //dev.SetFeatureValue("TriggerMode", "Off");
                    acq.SetParameter(SapAcquisition.Prm.EXT_TRIGGER_SOURCE, SapAcquisition.Val.SIGNAL_NAME_SHAFT_ENCODER_PHASE_B, true);
                //acq.SetParameter(SapAcquisition.Prm.EXT_TRIGGER_ENABLE, SapAcquisition.Val.EXT_TRIGGER_ON, bEnable);
                else
                    //dev.SetFeatureValue("TriggerMode", "On");
                    acq.SetParameter(SapAcquisition.Prm.EXT_TRIGGER_SOURCE, SapAcquisition.Val.SIGNAL_NAME_SHAFT_ENCODER_PHASE_A, true);
                //acq.SetParameter(SapAcquisition.Prm.EXT_TRIGGER_ENABLE, SapAcquisition.Val.EXT_TRIGGER_OFF, bEnable);

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        public void SetImageMirror(bool bDir)
        {
            dev.SetFeatureValue("ReverseX", bDir ? "Off" : "On");
        }

        public void SetCut(int x, int y, int w, int h)
        {
            this.ptCrop = new Point(x, y);
            this.sizeCrop = new Size(w, h);
        }

        public void SetCut(CamSight cs)
        {
            camSight = cs;
        }

        public void Snap()
        {
            while (!bParaSet)
            {
                Thread.Sleep(2);
            }
            try
            {
                bGrabed = false;
                m_bitmap = null;



                //acq.GetParameter(SapAcquisition.Prm.CROP_HEIGHT, out int h);
                //if (h != imgHeight) acq.SetParameter(SapAcquisition.Prm.CROP_HEIGHT, imgHeight, true);

                ////新建缓存
                //buffTrash = new SapBufferWithTrash(2, acq, SapBuffer.MemoryType.ScatterGather);
                //toBuff = new SapAcqToBuf(acq, buffTrash);

                ////创建
                //bool bAcq = acq.Create();
                //bool bBuff = buffTrash.Create();
                //bool bToBuff = toBuff.Create();

                ////绑定事件
                //toBuff.XferNotify += new SapXferNotifyHandler(xfer_XferNotify);
                //toBuff.XferNotifyContext = this;

                //触发采图
                //dev.SetFeatureValue("TriggerMode", "On");
                toBuff.Snap();
            }
            catch (System.Exception ex)
            {

            }
        }
        public void SetExposurePara(int imgHeight, bool bDir, string angle, int exposure, double gain, string sAddition = "")
        {
            bParaSet = false;
            try
            {
                //Task.Run(() =>
                //{
                //if (grayOffset > gain * 32 - 5) grayOffset = (int)(gain * 32 - 5);
                //if (grayOffset < -gain * 32 - 2) grayOffset = (int)(-gain * 32 - 2);


                //设置新的图像高度
                rotateAngle = angle;
                //销毁缓存
                toBuff.Destroy();
                buffTrash?.Destroy();
                int h;
                acq.GetParameter(SapAcquisition.Prm.CROP_HEIGHT, out h);
                if (h != imgHeight) acq.SetParameter(SapAcquisition.Prm.CROP_HEIGHT, imgHeight, true);


                string rev = "";

                dev.GetFeatureValue("ReverseX", out rev);
                if (rev != "Off" && bDir) dev.SetFeatureValue("ReverseX", bDir ? "Off" : "On");
                if (rev != "On" && !bDir) dev.SetFeatureValue("ReverseX", bDir ? "Off" : "On");
                //dev.SetFeatureValue("BlackLevel", grayOffset.ToString());
                dev.SetFeatureValue("TriggerMode", "On");
                //Thread.Sleep(50);
                //dev.GetFeatureValue("ExposureTime",out uint exp);
                //dev.GetFeatureValue("Gain", out double g);

                var cnt = 0;
                SET:
                bool bExp = true;
                bool bGain = true;
                if (exposure != -1) bExp = dev.SetFeatureValue("ExposureTime", exposure.ToString());
                if (gain != -1) bGain = dev.SetFeatureValue("Gain", gain.ToString());
                if (!bExp || !bGain)
                {
                    double pExp;
                    double pGain;
                    dev.GetFeatureValue("ExposureTime", out pExp);
                    dev.GetFeatureValue("Gain", out pGain);
                    if (pExp != exposure || pGain != gain)
                    {
                        var p = Path.Combine(Common.PathLog, $"Dalsa_{DateTime.Now.ToString("yyyy_MM_dd")}.txt");
                        using (var sw = new StreamWriter(p, true))
                        {
                            sw.WriteLine($"{DateTime.Now.ToLongTimeString()}     {sAddition}");
                            sw.WriteLine($"目标参数（exp,gain）:{exposure},{gain},设置后相机参数:{pExp},{pGain}");
                        }
                    }
                    cnt++;
                    if (cnt <= 3) goto SET;
                }



                bParaSet = true;//标记参数切换完成，然后才能启动采集图片
                //});

                if (imgHeight >= 200000) throw new Exception($"imgHeight={imgHeight}");
                if (exposure >= 200000) throw new Exception($"ExposureTime={exposure}");
                if (gain >= 200000) throw new Exception($"imgHeight={gain}");
                //dev.SetFeatureValue("TriggerMode", "On");

                //var b = dev.SetFeatureValue("AcquisitionLineRate", 2840);
                //acq.SetParameter(SapAcquisition.Prm.rate, SapAcquisition.Val.SIGNAL_NAME_SHAFT_ENCODER_PHASE_B, true);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString() + "\n" + ex.StackTrace);
                bParaSet = true;
            }
        }

        public string SetParaAsync(int imgHeight, double exposure, double gain, string sAddition = "")
        {
            string msg = string.Empty;
            bParaSet = false;
            try
            {
                //销毁缓存
                //toBuff.Destroy();
                //buffTrash?.Destroy();
                //int h = 0;
                //string rev = "";
                //acq.GetParameter(SapAcquisition.Prm.CROP_HEIGHT, out h);
                //if (h != imgHeight) acq.SetParameter(SapAcquisition.Prm.CROP_HEIGHT, imgHeight, true);
                //dev.SetFeatureValue("TriggerMode", "On");

                var cnt = 0;
            SET:
                bool bExp = true;
                bool bGain = true;
                double pExp = 0;
                double pGain = 0;
                if (exposure != -1) bExp = dev.SetFeatureValue("ExposureTime", exposure);
                if (gain != -1) bGain = dev.SetFeatureValue("Gain", gain);
                if (!bExp) msg += "SetFeatureValue（ExposureTime）Error ";
                if (!bGain) msg += "SetFeatureValue（Gain）Error ";

                dev.GetFeatureValue("ExposureTime", out pExp);
                dev.GetFeatureValue("Gain", out pGain);

                if (!bExp || !bGain || pExp != exposure || pGain != gain)
                {
                    msg += $"Dalsa设置相机参数失败,重试次数:{cnt},pSet:{exposure},{gain},pGet:{pExp},{pGain}";
                    cnt++;
                    if (cnt <= 3) goto SET;
                }


                bParaSet = true;//标记参数切换完成，然后才能启动采集图片
                //});

                //if (imgHeight >= 200000) throw new Exception($"imgHeight={imgHeight}");
                if (exposure >= 10000) throw new Exception($"ExposureTime={exposure}");
                if (gain >= 20) throw new Exception($"imgHeight={gain}");
                //dev.SetFeatureValue("TriggerMode", "On");

                //var b = dev.SetFeatureValue("AcquisitionLineRate", 2840);
                //acq.SetParameter(SapAcquisition.Prm.rate, SapAcquisition.Val.SIGNAL_NAME_SHAFT_ENCODER_PHASE_B, true);

                //新建缓存
                //buffTrash = new SapBufferWithTrash(2, acq, SapBuffer.MemoryType.ScatterGather);
                //toBuff = new SapAcqToBuf(acq, buffTrash);

                //创建
                //bool bAcq = acq.Create();
                //bool bBuff = buffTrash.Create();
                //bool bToBuff = toBuff.Create();

                //绑定事件
                //toBuff.XferNotify += new SapXferNotifyHandler(xfer_XferNotify);
                //toBuff.XferNotifyContext = this;
                return msg;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString() + "\n" + ex.StackTrace);
                msg = ex.ToString();
                bParaSet = true;
                return msg;
            }
        }
        public void SnapAsync()
        {

            try
            {
                m_bitmap = null;
                bGrabed = false;
                //触发采图
                //dev.SetFeatureValue("TriggerMode", "On");
                toBuff.Snap();
            }
            catch (System.Exception ex)
            {

            }
        }

        public void SetPara(int imgHeight, int exposure, double gain, string sAddition = "")
        {
            bParaSet = false;
            try
            {
                //Task.Run(() =>
                //{
                //if (grayOffset > gain * 32 - 5) grayOffset = (int)(gain * 32 - 5);
                //if (grayOffset < -gain * 32 - 2) grayOffset = (int)(-gain * 32 - 2);


                //设置新的图像高度
                //rotateAngle = angle;
                //销毁缓存
                toBuff.Destroy();
                buffTrash?.Destroy();
                int h = 0;
                string rev = "";
                acq.GetParameter(SapAcquisition.Prm.CROP_HEIGHT, out h);
                if (h != imgHeight) acq.SetParameter(SapAcquisition.Prm.CROP_HEIGHT, imgHeight, true);

                //dev.GetFeatureValue("ReverseX", out rev);
                //if (rev != "Off" && bDir) dev.SetFeatureValue("ReverseX", bDir ? "Off" : "On");
                //if (rev != "On" && !bDir) dev.SetFeatureValue("ReverseX", bDir ? "Off" : "On");
                //dev.SetFeatureValue("BlackLevel", grayOffset.ToString());
                dev.SetFeatureValue("TriggerMode", "On");
                //Thread.Sleep(50);
                //dev.GetFeatureValue("ExposureTime",out uint exp);
                //dev.GetFeatureValue("Gain", out double g);

                var cnt = 0;
            SET:
                bool bExp = true;
                bool bGain = true;
                double pExp = 0;
                double pGain = 0;
                if (exposure != -1) bExp = dev.SetFeatureValue("ExposureTime", exposure.ToString());
                if (gain != -1) bGain = dev.SetFeatureValue("Gain", gain.ToString());
                if (!bExp || !bGain)
                {
                    dev.GetFeatureValue("ExposureTime", out pExp);
                    dev.GetFeatureValue("Gain", out pGain);
                    //if (pExp != exposure || pGain != gain)
                    //{
                    //    var p = Path.Combine(PCs.PathLog + @"\DalsaCam\", $"Dalsa_{DateTime.Now.ToString("yyyy_MM_dd")}.txt");
                    //    using (var sw = new StreamWriter(p,true))
                    //    {
                    //        sw.WriteLine($"{DateTime.Now.ToLongTimeString()}     {sAddition}");
                    //        sw.WriteLine($"目标参数（exp,gain）:{exposure},{gain},设置后相机参数:{pExp},{pGain}");
                    //    }
                    //}
                    cnt++;
                    if (cnt <= 3) goto SET;
                }



                bParaSet = true;//标记参数切换完成，然后才能启动采集图片
                //});

                if (imgHeight >= 200000) throw new Exception($"imgHeight={imgHeight}");
                if (exposure >= 200000) throw new Exception($"ExposureTime={exposure}");
                if (gain >= 200000) throw new Exception($"imgHeight={gain}");
                //dev.SetFeatureValue("TriggerMode", "On");

                //var b = dev.SetFeatureValue("AcquisitionLineRate", 2840);
                //acq.SetParameter(SapAcquisition.Prm.rate, SapAcquisition.Val.SIGNAL_NAME_SHAFT_ENCODER_PHASE_B, true);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString() + "\n" + ex.StackTrace);
                bParaSet = true;
            }
        }

        public void SetParaEx(int imgHeight, bool bDir, string angle)
        {
            try
            {
                //销毁缓存
                //toBuff.Destroy();
                //buffTrash?.Destroy();

                ////设置新的图像高度
                //rotateAngle = angle;

                //acq.GetParameter(SapAcquisition.Prm.CROP_HEIGHT, out int h);
                //if (h != imgHeight) acq.SetParameter(SapAcquisition.Prm.CROP_HEIGHT, imgHeight, true);

                //dev.GetFeatureValue("ReverseX", out string rev);
                //if (rev != "Off" && bDir) dev.SetFeatureValue("ReverseX", bDir ? "Off" : "On");
                //if (rev != "On" && !bDir) dev.SetFeatureValue("ReverseX", bDir ? "Off" : "On");

            }
            catch (Exception ex)
            {

            }
        }

        public void Grab()
        {
            bGrabed = false;
            //销毁缓存
            toBuff.Destroy();
            buffTrash?.Destroy();

            //设置新的图像高度
            acq.SetParameter(SapAcquisition.Prm.CROP_HEIGHT, 500, true);

            //新建缓存
            buffTrash = new SapBufferWithTrash(2, acq, SapBuffer.MemoryType.ScatterGather);
            toBuff = new SapAcqToBuf(acq, buffTrash);

            //创建
            bool bAcq = acq.Create();
            bool bBuff = buffTrash.Create();
            bool bToBuff = toBuff.Create();

            //绑定事件
            toBuff.XferNotify += new SapXferNotifyHandler(xfer_XferNotify);
            toBuff.XferNotifyContext = this;

            //触发采图
            dev.SetFeatureValue("TriggerMode", "Off");
            toBuff.Grab();
        }

        public void Abort()
        {
            try
            {
                toBuff.Abort();
            }
            catch (Exception ex)
            {
            }
        }

        void xfer_XferNotify(object sender, SapXferNotifyEventArgs argsNotify)
        {
            //Form1 GrabDlg = argsNotify.Context as Form1;

            //buffTrash.Save("D:\\DALSA.BMP", "-format bmp");
            //MessageBox.Show("success");

            IntPtr ptr;
            buffTrash.GetAddress(out  ptr);
            Bitmap bit = BufferToBitmap(ptr, buffTrash.Width, buffTrash.Height);
            if (rotateAngle == "90") bit.RotateFlip(RotateFlipType.Rotate90FlipNone);
            else if (rotateAngle == "180") bit.RotateFlip(RotateFlipType.Rotate180FlipNone);
            else if (rotateAngle == "270") bit.RotateFlip(RotateFlipType.Rotate270FlipNone);
            //bit.Save("D:\\DALSA.BMP");
            //var w = sizeCrop.Width;
            //var h = sizeCrop.Height;
            //if (sizeCrop.Width > bit.Width) w = bit.Width;
            //if (sizeCrop.Height > bit.Height) h = bit.Height;
            //if (bCrop) m_bitmap = crop(bit, ptCrop, new Size(w, h));
            //else m_bitmap = bit;
            m_bitmap = bit;
            bGrabed = true;
        }

        public Bitmap BufferToBitmap(IntPtr ImageP, int width, int height)
        {
            #region BufferToBitmap

            //获取Hobject变量的指针
            //HOperatorSet.GetImagePointer3(ho_Image,out R,out G,out B,out type,out width,out height);
            //
            Bitmap imagee = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
            BitmapData imageData = imagee.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);

            //
            //建立缓存数据
            byte[] bitdata = new byte[width * width];
            int hang = height;
            int lie = width;
            //将画板填充颜色
            ColorPalette pal = imagee.Palette;
            for (int i = 0; i <= 255; i++)
            {
                pal.Entries[i] = Color.FromArgb(255, i, i, i);
            }
            imagee.Palette = pal;
            //通过中间数组将HObject转化为Image
            for (int Num = 0; Num < lie; Num++)
            {
                IntPtr inptr = ImageP + ((Num) * hang);
                IntPtr imptr = imageData.Scan0 + (Num * hang);

                System.Runtime.InteropServices.Marshal.Copy(inptr, bitdata, 0, hang);
                System.Runtime.InteropServices.Marshal.Copy(bitdata, 0, imptr, hang);

            }
            imagee.UnlockBits(imageData);

            return imagee;

            #endregion
        }

        public void Close()
        {
            try
            {
                //销毁缓存
                toBuff.Destroy();
                buffTrash?.Destroy();
                dev.Destroy();
                acq.Destroy();
            }
            catch (Exception ex)
            {

            }
        }

        private static Bitmap crop(Bitmap bit, Point pt, Size size)
        {
            Rectangle cropRect = new Rectangle(pt.X, pt.Y, size.Width, size.Height);
            Bitmap target = new Bitmap(cropRect.Width, cropRect.Height);
            using (Graphics g = Graphics.FromImage(target))
            {
                g.DrawImage(bit, new Rectangle(0, 0, target.Width, target.Height), cropRect, GraphicsUnit.Pixel);
            }
            return target;
        }

    }
}

